
package com.yuanmei.stockeyes.data;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.database.sqlite.SQLiteStatement;
import android.util.Log;
import financedata.historicalquotes.HistoryRequestProvider;
import financedata.historicalquotes.HistoryRequestProvider.RequestSourceType;
import financedata.historicalquotes.IHistoryRequest;
import financedata.historicalquotes.HistoricalQuote;
import financedata.historicalquotes.Interval;

import com.yuanmei.stockeyes.artifacts.Constants;
import com.yuanmei.stockeyes.artifacts.Extensions;

public class HistoryQuotesDataBase {
    public final static String TAG       = "HistoryQuotesDataBase";
    public final static String day_suffix    = "_day";
    public final static String week_suffix   = "_week";
    public final static String month_suffix  = "_month";

    // history quotes table
    public final static String KEY_HISTAB_OPEN     = "open";
    public final static String KEY_HISTAB_LOW      = "low";
    public final static String KEY_HISTAB_HIGH     = "high";
    public final static String KEY_HISTAB_CLOSE    = "close";
    public final static String KEY_HISTAB_AMOUNT   = "amount";
    public final static String KEY_HISTAB_VOLUME   = "volume";
    public final static String KEY_HISTAB_DATE     = "date";
    
    private final static int MIN_QUOTES_CNTS   = 1;
    private final static int INIT_UPDATE_COUNT = (10 * 240); // 3年交易日
    private final static SimpleDateFormat sHisDateFmt = new  SimpleDateFormat("yyyy-MM-dd");

//    private final static Map<String , RequestSourceType> sHisReqSrcTypeMap = 
//            new HashMap<String , RequestSourceType>(){{
//        put("^sh000001", RequestSourceType.QUANDOL_GOOGLE);
//        put("^sz399001", RequestSourceType.QUANDOL_GOOGLE);
//        put("^sh000300", RequestSourceType.QUANDOL_GOOGLE);
//    }};

    private HistoryQuoteDBOpenHelper mHistoryDBOpenHelper;
    
    public class HistoryRecord {
        public Float mOpen;
        public Float mLow;
        public Float mHigh;
        public Float mClose;
        public Float mAmount;
        public long  mVolume;
        public long  mDate;
        
        public HistoryRecord(Float open, Float low, Float high, Float close,
                Float amount, long volume, long date) {
            mOpen  = open;
            mLow   = low;
            mHigh  = high;
            mClose = close;
            mAmount = amount;
            mVolume   = volume;
            mDate     = date;
        }
    }
    
    public class HisReqParms {
        public String mReqSymbol;
        public RequestSourceType mReqSrcType;

        public HisReqParms(String reqSymbol, RequestSourceType srcType) {
            mReqSymbol  = reqSymbol;
            mReqSrcType = srcType;
        }
    }


    public HistoryQuotesDataBase(Context context) {
        mHistoryDBOpenHelper = new HistoryQuoteDBOpenHelper(context);
    }

    private static String getTableName(String symbol_code, Interval interval){
        
        String tab_name = null;
        if (symbol_code.startsWith("^")) {
            symbol_code = symbol_code.substring(1);
        }
        if (interval == Interval.DAILY) {
            tab_name = symbol_code + day_suffix;
        } else if (interval == Interval.WEEKLY) {
            tab_name = symbol_code + week_suffix;
        } else if (interval == Interval.MONTHLY) {
            tab_name = symbol_code + month_suffix;
        } else {
            return null;
        }

        return tab_name;
    }

    private HisReqParms buildPublicHistoryDataReqParms(String symbol_code, String m_code,
                                                            int market_id) {
        RequestSourceType srcType;
        if (symbol_code.startsWith("^")) {
            srcType = RequestSourceType.QUANDOL_GOOGLE;
        } else {
            srcType = RequestSourceType.YAHOO_FINANCE;
        }

        String reqSymbol;
        if (srcType == RequestSourceType.QUANDOL_GOOGLE) {
            String market_name;
            if (market_id == 1) {
                market_name = "SHA";
            } else {
                market_name = "SHE";
            }
            reqSymbol = market_name + "_" + m_code;
        } else {
            String market_name;
            if (market_id == 1) {
                market_name = "SS";
            } else {
                market_name = "SZ";
            }
            reqSymbol = m_code + "." + market_name;
        }

        HisReqParms ret = new HisReqParms(reqSymbol, srcType);

        return ret;
    }

    private HisReqParms buildYuanMeiHistoryDataReqParms(String symbol_code, String m_code,
                                                            int market_id) {
        RequestSourceType srcType  = RequestSourceType.YUANMEI_FINANCE;
        String reqSymbol = market_id + m_code;
        HisReqParms ret = new HisReqParms(reqSymbol, srcType);
        return ret;
    }

    private HisReqParms buildMoney163ReqParms(String symbol_code, String m_code,
                                                            int market_id) {
        RequestSourceType srcType  = RequestSourceType.MONEY163_FINANCE;
        String reqSymbol;
        if (2 == market_id) {
            // shengzhen market
            reqSymbol = "1" + m_code;
        } else {
            // shanghai market
            reqSymbol = "0" + m_code;
        }

        HisReqParms ret = new HisReqParms(reqSymbol, srcType);
        return ret;
    }

    private long getIntervalMilliSeconds(Interval interval){
        if (interval == Interval.DAILY) {
            return Constants.DAY_TO_MILLSECONDS;
        } else if (interval == Interval.WEEKLY) {
            return Constants.DAY_TO_MILLSECONDS * 7;
        } else if (interval == Interval.MONTHLY) {
            return Constants.DAY_TO_MILLSECONDS * 30;
        }
        return 0;
    }

    public void deleteHisQuotesTable(String symbol_code) {
        try {
            SQLiteDatabase database = getWritableDatabase();
            deleteHisQuotesTable(symbol_code, database);
        } catch (Exception e) {
            // 强行删除
        }
    }

    private static void deleteHisQuotesTable(String symbol_code, SQLiteDatabase database) {

        String tab_name = getTableName(symbol_code, Interval.DAILY);
        String sql = "DROP TABLE " + tab_name;
        database.execSQL(sql);

        tab_name = getTableName(symbol_code, Interval.WEEKLY);
        sql = "DROP TABLE " + tab_name;
        database.execSQL(sql);

        tab_name = getTableName(symbol_code, Interval.MONTHLY);
        sql = "DROP TABLE " + tab_name;
        database.execSQL(sql);
    }

    public void createHisQuotesTable(String symbol_code) {
        SQLiteDatabase database = getWritableDatabase();
        createHisQuotesTable(symbol_code, database);
    }

    private static void createHisQuotesTable(String symbol_code, SQLiteDatabase database) {
        String tab_name = getTableName(symbol_code, Interval.DAILY);
        String sql = "CREATE TABLE IF NOT EXISTS " + tab_name
                + " (open FLOAT NOT NULL," + " low FLOAT NOT NULL,"
                + " high FLOAT NOT NULL," + " close FLOAT NOT NULL,"
                + " amount FLOAT NOT NULL," + " volume BIGINT NOT NULL,"
                + " date BIGINT UNIQUE NOT NULL PRIMARY KEY);";
        database.execSQL(sql);

        tab_name = getTableName(symbol_code, Interval.WEEKLY);
        sql = "CREATE TABLE IF NOT EXISTS " + tab_name
                + " (open FLOAT NOT NULL," + " low FLOAT NOT NULL,"
                + " high FLOAT NOT NULL," + " close FLOAT NOT NULL,"
                + " amount FLOAT NOT NULL," + " volume BIGINT NOT NULL,"
                + " date BIGINT UNIQUE NOT NULL PRIMARY KEY);";
        database.execSQL(sql);

        tab_name = getTableName(symbol_code, Interval.MONTHLY);
        sql = "CREATE TABLE IF NOT EXISTS " + tab_name
                + " (open FLOAT NOT NULL," + " low FLOAT NOT NULL,"
                + " high FLOAT NOT NULL," + " close FLOAT NOT NULL,"
                + " amount FLOAT NOT NULL," + " volume BIGINT NOT NULL,"
                + " date BIGINT UNIQUE NOT NULL PRIMARY KEY);";
        database.execSQL(sql);
    }
    
    public static void initHistoryQuotesTable(String symbol_code, SQLiteDatabase database) {
        createHisQuotesTable(symbol_code, database);
    }

    private void insertHisQuotes(String tab_name, List<HistoricalQuote> hisQuotes) {
        
        SQLiteDatabase database = getWritableDatabase(); 
        database.beginTransaction();
        try {
            ContentValues values = new ContentValues();
            for (HistoricalQuote quote :  hisQuotes){
                values.clear();
                values.put(KEY_HISTAB_OPEN, 
                        quote.getOpen().setScale(2, BigDecimal.ROUND_HALF_UP).floatValue());
                values.put(KEY_HISTAB_LOW,  
                        quote.getLow().setScale(2, BigDecimal.ROUND_HALF_UP).floatValue());
                values.put(KEY_HISTAB_HIGH, 
                        quote.getHigh().setScale(2, BigDecimal.ROUND_HALF_UP).floatValue());
                values.put(KEY_HISTAB_CLOSE,
                        quote.getClose().setScale(2, BigDecimal.ROUND_HALF_UP).floatValue());
                values.put(KEY_HISTAB_AMOUNT, 
                        quote.getAmount().setScale(2, BigDecimal.ROUND_HALF_UP).floatValue());
                values.put(KEY_HISTAB_VOLUME, quote.getVolume());
                values.put(KEY_HISTAB_DATE, Extensions.formatDateToDayLong(quote.getDate()) );
                //database.insert(tab_name, null, values);
                database.insertWithOnConflict(tab_name, null, values, SQLiteDatabase.CONFLICT_REPLACE);
            }
            database.setTransactionSuccessful();
        } catch (Exception e) {
            Log.e(TAG, "Db meet Exception=" + e);
            e.printStackTrace();
        } finally {
            database.endTransaction();
        }
        
        if (tab_name.endsWith("day")) {
           // dumpTab(tab_name);
        }
    }

    private void updateAllHistoryTabs(String symbol_code, List<HistoricalQuote> hisQuotes) {
        String day_tab   = getTableName(symbol_code, Interval.DAILY);
        String week_tab  = getTableName(symbol_code, Interval.WEEKLY);
        String month_tab = getTableName(symbol_code, Interval.MONTHLY);

        SQLiteDatabase database = getWritableDatabase();
        database.beginTransaction();

        String updateDaySql = "INSERT OR REPLACE INTO " + day_tab
                + " (" + KEY_HISTAB_OPEN + ","
                + KEY_HISTAB_LOW + ","
                + KEY_HISTAB_HIGH + ","
                + KEY_HISTAB_CLOSE + ","
                + KEY_HISTAB_AMOUNT + ","
                + KEY_HISTAB_VOLUME + ","
                + KEY_HISTAB_DATE + ")"
                + " VALUES (?,?,?,?,?,?,?)";
        SQLiteStatement daySqlStat = database.compileStatement(updateDaySql);

        String updateWeekSql = "INSERT OR REPLACE INTO " + week_tab
                + " (" + KEY_HISTAB_OPEN + ","
                + KEY_HISTAB_LOW + ","
                + KEY_HISTAB_HIGH + ","
                + KEY_HISTAB_CLOSE + ","
                + KEY_HISTAB_AMOUNT + ","
                + KEY_HISTAB_VOLUME + ","
                + KEY_HISTAB_DATE + ")"
                + " VALUES (?,?,?,?,?,?,?)";
        SQLiteStatement weekSqlStat = database.compileStatement(updateWeekSql);

        String updateMonthSql = "INSERT OR REPLACE INTO " + month_tab
                + " (" + KEY_HISTAB_OPEN + ","
                + KEY_HISTAB_LOW + ","
                + KEY_HISTAB_HIGH + ","
                + KEY_HISTAB_CLOSE + ","
                + KEY_HISTAB_AMOUNT + ","
                + KEY_HISTAB_VOLUME + ","
                + KEY_HISTAB_DATE + ")"
                + " VALUES (?,?,?,?,?,?,?)";
        SQLiteStatement monthSqlStat = database.compileStatement(updateMonthSql);

        int day_updatecnts   = 0;
        int week_updatecnts  = 0;
        int month_updatecnts = 0;
        try {
            int wyear_cursor = -1;
            int week_cursor  = -1;

            int myear_cursor = -1;
            int month_cursor = -1;

            long   week_date     = 0;
            double week_open     = 0;
            double week_high     = Double.MIN_VALUE;
            double week_low      = Double.MAX_VALUE;
            double week_close    = 0;
            double week_amount  = 0;
            long   week_volume   = 0;
            int    week_addcnts = 0;

            long   month_date     = 0;
            double month_open     = 0;
            double month_high     = Double.MIN_VALUE;
            double month_low      = Double.MAX_VALUE;
            double month_close    = 0;
            double month_amount  = 0;
            long   month_volume   = 0;
            int    month_addcnts = 0;

            long   quote_date = 0;
            long   last_quotedate = 0;

            Collections.reverse(hisQuotes);
            for (HistoricalQuote quote :  hisQuotes){
                double quote_open     = quote.getOpen().setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                double quote_low      = quote.getLow().setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                double quote_high     = quote.getHigh().setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                double quote_close    = quote.getClose().setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                double quote_amounts  = quote.getAmount().setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                long   quote_volume   = quote.getVolume();
                if (0 == quote_open || 0 == quote_close) {
                    continue;
                }

                last_quotedate = quote_date;
                quote_date     = Extensions.formatDateToDayLong(quote.getDate());


                daySqlStat.clearBindings();
                daySqlStat.bindDouble(1, quote_open);
                daySqlStat.bindDouble(2, quote_low);
                daySqlStat.bindDouble(3, quote_high);
                daySqlStat.bindDouble(4, quote_close);
                daySqlStat.bindDouble(5, quote_amounts);
                daySqlStat.bindLong(6,   quote_volume);
                daySqlStat.bindLong(7,   quote_date);
                daySqlStat.executeInsert();
                day_updatecnts++;

//                if (symbol_code.equalsIgnoreCase("^sh000001")) {
//                    Log.d(TAG, "quote_" + day_updatecnts + " date =" + quote_date);
//                }

                int quote_year = quote.getDate().get(Calendar.YEAR);
                int quote_moth = quote.getDate().get(Calendar.MONTH);
                int quote_week = quote.getDate().get(Calendar.WEEK_OF_YEAR);

                if (wyear_cursor < 0 || week_cursor < 0) {
                    wyear_cursor  = quote_year;
                    week_cursor  = quote_week;
                }

                if ((quote_year > wyear_cursor)
                        || (quote_week > week_cursor)) {
                    if (week_addcnts > 0) {
                        weekSqlStat.clearBindings();
                        weekSqlStat.bindDouble(1, week_open);
                        weekSqlStat.bindDouble(2, week_low);
                        weekSqlStat.bindDouble(3, week_high);
                        weekSqlStat.bindDouble(4, week_close);
                        weekSqlStat.bindDouble(5, week_amount);
                        weekSqlStat.bindLong(6, week_volume);
                        weekSqlStat.bindLong(7, week_date);
                        weekSqlStat.executeInsert();
                        week_updatecnts++;

                        // Restart week data collect
                        week_date = 0;
                        week_open = 0;
                        week_high = Double.MIN_VALUE;
                        week_low = Double.MAX_VALUE;
                        week_close = 0;
                        week_amount = 0;
                        week_volume = 0;
                        week_addcnts = 0;
                    } else {
                        Log.w(TAG, "Get week's data error: date=" + quote_date
                                + ", year_cursor=" + wyear_cursor + ", week_cursor=" + week_cursor
                                + ", last_quotedate=" + last_quotedate);
                    }
                    wyear_cursor = quote_year;
                    week_cursor = quote_week;
                }
                week_amount += quote_amounts;
                week_volume  += quote_volume;
                if (0 == week_open) {
                    week_open = quote_open;
                }
                if (quote_high > week_high) {
                    week_high = quote_high;
                }
                if (quote_low < week_low) {
                    week_low = quote_low;
                }
                week_close = quote_close;
                week_date  = quote_date;
                week_addcnts++;


                // Month
                if (myear_cursor < 0 || month_cursor < 0) {
                    myear_cursor = quote_year;
                    month_cursor = quote_moth;
                }

                if ((quote_year > myear_cursor)
                        || (quote_moth > month_cursor)) {
                    if (month_addcnts > 0) {
                        monthSqlStat.clearBindings();
                        monthSqlStat.bindDouble(1, month_open);
                        monthSqlStat.bindDouble(2, month_low);
                        monthSqlStat.bindDouble(3, month_high);
                        monthSqlStat.bindDouble(4, month_close);
                        monthSqlStat.bindDouble(5, month_amount); // always set to 0
                        monthSqlStat.bindLong(6,   month_volume);
                        monthSqlStat.bindLong(7,   month_date);
                        monthSqlStat.executeInsert();
                        month_updatecnts++;
                        // restart month add
                        month_date     = 0;
                        month_open     = 0;
                        month_high     = Double.MIN_VALUE;
                        month_low      = Double.MAX_VALUE;
                        month_close    = 0;
                        month_amount  = 0;
                        month_volume   = 0;
                        month_addcnts = 0;
                    } else {
                        Log.w(TAG, "Get month's data error: date=" + quote_date
                                + ", year_cursor=" + myear_cursor + ", month_cursor=" + month_cursor
                                + ", last_quotedate=" + last_quotedate);
                    }
                    myear_cursor = quote_year;
                    month_cursor = quote_moth;
                } 
                
                month_volume  += quote_volume;
                month_amount += quote_amounts;
                if (0 == month_open) {
                    month_open = quote_open;
                }
                if (quote_high > month_high) {
                    month_high = quote_high;
                }
                if (quote_low < month_low) {
                    month_low = quote_low;
                }
                month_close = quote_close;
                month_date  = quote_date;
                month_addcnts++;
            }
            database.setTransactionSuccessful();

//            Log.i(TAG, "Update Stock(" + symbol_code + ")'s hisquotes tab,days=" + day_updatecnts
//                + ", weeks=" + week_updatecnts + ", months=" + month_updatecnts);
        } catch (Exception e) {
            Log.e(TAG, "Db meet Exception=" + e);
            e.printStackTrace();
        } finally {
            database.endTransaction();
        }
    }

    private boolean isLastRecordOutOfDate(Calendar curr_date, Calendar last_rec_date, Interval interval) {
        boolean ret = false;
        
        if (interval == Interval.DAILY) {
            int back_days = 0;
            if (curr_date.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
                back_days = 1; 
            } else if (curr_date.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
                back_days = 2; 
            }

            if (curr_date.get(Calendar.HOUR_OF_DAY) < 15) {
                back_days += 1;
            }

            if ((last_rec_date.get(Calendar.YEAR) < curr_date.get(Calendar.YEAR)) ||
                (last_rec_date.get(Calendar.DAY_OF_YEAR) < (curr_date.get(Calendar.DAY_OF_YEAR) - back_days))) {
                SimpleDateFormat data_fmt = new SimpleDateFormat("yyyyMMdd");
                Log.i(TAG, "Need update dayline, last record's date=" + data_fmt.format(last_rec_date.getTime())
                            + ", current date=" + data_fmt.format(curr_date.getTime()));
                return true;
            }
        } else if ((interval == Interval.WEEKLY)) {
            if ((last_rec_date.get(Calendar.YEAR) < curr_date.get(Calendar.YEAR))
                    || (last_rec_date.get(Calendar.WEEK_OF_YEAR) < (curr_date.get(Calendar.WEEK_OF_YEAR)))) {
                return true;
            }
        } else if ((interval == Interval.MONTHLY)) {
            if ((last_rec_date.get(Calendar.YEAR) < curr_date.get(Calendar.YEAR))
                    || (last_rec_date.get(Calendar.MONTH) < (curr_date.get(Calendar.MONTH)))) {
                return true;
            }
        }
        return ret;
    }
    /*
    private int getTabCounts(String tab_name) { 
        SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
        builder.setTables(tab_name);
        String[] columns = {KEY_HISTAB_DATE};
        Cursor resCursor = builder.query(getReadableDatabase(), columns, null,
                null, "", "", null, null);
        int cnt = resCursor.getCount();
        resCursor.close();
        return cnt;
    }
    

    private void dumpTab(String tab_name) { 
        SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
        builder.setTables(tab_name);
        String[] columns = 
            { KEY_HISTAB_OPEN, 
              KEY_HISTAB_LOW,  
              KEY_HISTAB_HIGH, 
              KEY_HISTAB_CLOSE,
              KEY_HISTAB_AMOUNT,
              KEY_HISTAB_VOLUME, 
              KEY_HISTAB_DATE};

       String orderby = KEY_HISTAB_DATE + " DESC";

       Cursor resCursor = builder.query(getReadableDatabase(), columns, null,
              null, "", "", orderby, null);
       resCursor.moveToFirst();
       Calendar rec_date = Calendar.getInstance();
       Log.i(TAG, "DumpTable:" + tab_name + " counts=" + resCursor.getCount());
       if (resCursor.getCount() > 0) {
           int idx = 0;
           do {
               try {
                   long rec_ms = resCursor.getLong(resCursor.getColumnIndex(KEY_HISTAB_DATE));
                   rec_date.setTimeInMillis(rec_ms);
     
                   Log.i(TAG,"Row_" + (idx++) + ": O:" + resCursor.getFloat(resCursor.getColumnIndex(KEY_HISTAB_OPEN))
                            + " L:" + resCursor.getFloat(resCursor.getColumnIndex(KEY_HISTAB_LOW)) 
                            + " H:" + resCursor.getFloat(resCursor.getColumnIndex(KEY_HISTAB_HIGH))
                            + " C:" + resCursor.getFloat(resCursor.getColumnIndex(KEY_HISTAB_CLOSE))
                            + " ADJ_C:" + resCursor.getFloat(resCursor.getColumnIndex(KEY_HISTAB_AMOUNT))
                            + " VOL:" + resCursor.getLong(resCursor.getColumnIndex(KEY_HISTAB_VOLUME))
                            + " DATE:" + sHisDateFmt.format(rec_date.getTime()));
                } catch (Exception e) {
                   Log.e(TAG, "Get HistoryRecord from cusror error, exception=" + e);
                   e.printStackTrace();
                   break;
               } 
           } while (resCursor.moveToNext());
       }
       
       resCursor.close();
    }
    */

    private HashMap<String, Object> mAsyncUpdateLockForStock = new HashMap<String, Object>();
    private  Object getAsyncUpdateLockOfStock(String symbol) {
        if (mAsyncUpdateLockForStock.containsKey(symbol)) {
            return mAsyncUpdateLockForStock.get(symbol);
        }
        mAsyncUpdateLockForStock.put(symbol, new Object());
        return mAsyncUpdateLockForStock.get(symbol);
    }

    public boolean updateTabData(String symbol_code, String m_code,
                                        int market_id) {
        Object lockForStock = getAsyncUpdateLockOfStock(symbol_code);
        synchronized (lockForStock) {
            return updateTabDataLocked(symbol_code, m_code, market_id);
        }
    }

    private boolean updateTabDataLocked(String symbol_code, String m_code,
            int market_id) {

        // 只更新日线
//        if (interval != Interval.DAILY) {
//            return true;
//        }
//
        String tab_name = getTableName(symbol_code, Interval.DAILY);
        SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
        builder.setTables(tab_name);
        String[] columns = {KEY_HISTAB_DATE};
        String orderby = KEY_HISTAB_DATE + " DESC";
        Cursor resCursor = builder.query(getReadableDatabase(), columns, null,
                null, "", "", orderby, null);
        resCursor.moveToFirst(); 
        int curr_cnts = resCursor.getCount();
        long last_rec_day = Constants.DAY_LONG_MIN;
        if (curr_cnts > 0) {
            last_rec_day = resCursor.getLong(resCursor.getColumnIndex(KEY_HISTAB_DATE)); 
        }
        resCursor.close();
        Calendar last_rec_date = Extensions.formatDayLongToDate(last_rec_day);

        Calendar curr_date   = Calendar.getInstance();
        curr_date.setTimeInMillis(System.currentTimeMillis());

        boolean isNeedReqData = false;
//        Log.d(TAG,"The Table:" + tab_name
//                + " last_rec_day:" + last_rec_day
//                + " last_rec_date=" + sHisDateFmt.format(last_rec_date.getTime())
//                + " record_cnts=" + curr_cnts);
        if (curr_cnts >= MIN_QUOTES_CNTS) {
            isNeedReqData = isLastRecordOutOfDate(curr_date, last_rec_date, Interval.DAILY);
        } else {
            isNeedReqData = true;
//            last_rec_date.setTimeInMillis(current_time_ms
//                    - (INIT_UPDATE_COUNT * getIntervalMilliSeconds(interval)));
            // 上证指数的第一个交易日
            last_rec_date.set(1990, 12, 19);
        }
 
        HisReqParms reqParms = null;
        if (isNeedReqData) {
            long startTime = System.currentTimeMillis();
            long endTime;
            //reqParms = buildYuanMeiHistoryDataReqParms(symbol_code, m_code, market_id);
            reqParms = buildMoney163ReqParms(symbol_code, m_code, market_id);
            IHistoryRequest his_req = HistoryRequestProvider.createHisReq(
                    reqParms.mReqSymbol, last_rec_date, curr_date, Interval.DAILY, reqParms.mReqSrcType);
            List<HistoricalQuote> histQuotes = his_req.getResult();
            if (histQuotes == null) {
                return false;
            }

//            endTime=System.currentTimeMillis();
//            Log.d(TAG, "Download stock(" + symbol_code + ") history quotes(" + histQuotes.size()
//                +") from " + sHisDateFmt.format(last_rec_date.getTime())
//                + " to " + sHisDateFmt.format(curr_date.getTime())
//                + ", use " + (endTime - startTime) + "ms");
//
//            startTime =  endTime;
            if (histQuotes.size() > 0) {
                //insertHisQuotes(tab_name, histQuotes); // 更新日线表
                updateAllHistoryTabs(symbol_code, histQuotes);
             }
            endTime=System.currentTimeMillis();
            Log.i(TAG, "Update stock(" + symbol_code + ")'s all history table use " + (endTime - startTime) + "ms");
        }
        return true;
    }

    public List<HistoryRecord> getLastNumRecords(String symbol_code,
            Interval interval, int lastNum) {
        String tab_name = getTableName(symbol_code, interval);
        if (null == tab_name)
            return null;

        Cursor resCursor = null;
        try {
            SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
            builder.setTables(tab_name);
            String[] columns = { KEY_HISTAB_OPEN, KEY_HISTAB_LOW, KEY_HISTAB_HIGH,
                    KEY_HISTAB_CLOSE, KEY_HISTAB_AMOUNT, KEY_HISTAB_VOLUME,
                    KEY_HISTAB_DATE };

            String orderby = KEY_HISTAB_DATE + " DESC";
            String limit = null;
            if (lastNum > 0) {
                limit = Integer.toString(lastNum);
            }
            resCursor = builder.query(getReadableDatabase(), columns, null,
                    null, "", "", orderby, limit);
        } catch (Exception e) {
            Log.w(TAG, "Qurery table:" + tab_name + " fail, will recrea");
            deleteHisQuotesTable(symbol_code);
            createHisQuotesTable(symbol_code);
            return null;
        }
 
        if (resCursor.getCount() <= 0) {
            return null;
        }
        List<HistoryRecord> allRecs = new ArrayList<HistoryRecord>();
        resCursor.moveToFirst();
        do {
            try {
                HistoryRecord rec = new HistoryRecord(
                        resCursor.getFloat(resCursor
                                .getColumnIndex(KEY_HISTAB_OPEN)),
                        resCursor.getFloat(resCursor
                                .getColumnIndex(KEY_HISTAB_LOW)),
                        resCursor.getFloat(resCursor
                                .getColumnIndex(KEY_HISTAB_HIGH)),
                        resCursor.getFloat(resCursor
                                .getColumnIndex(KEY_HISTAB_CLOSE)),
                        resCursor.getFloat(resCursor
                                .getColumnIndex(KEY_HISTAB_AMOUNT)),
                        resCursor.getLong(resCursor
                                .getColumnIndex(KEY_HISTAB_VOLUME)),
                        resCursor.getLong(resCursor
                                .getColumnIndex(KEY_HISTAB_DATE)));
                allRecs.add(rec);
            } catch (Exception e) {
                Log.e(TAG, "Get HistoryRecord from cusror error, exception=" + e);
                return null;
            }
        } while (resCursor.moveToNext());
        return allRecs;
    }
    
    private SQLiteDatabase getReadableDatabase() {
        return mHistoryDBOpenHelper.getReadableDatabase();
    }

    private SQLiteDatabase getWritableDatabase() {
        return mHistoryDBOpenHelper.getWritableDatabase();
    }

}
